#ifndef TCP_SOCKET_H
#define TCP_SOCKET_H

#include <QtNetwork>

#include "tcp_agreement.h"
#include <QByteArray>
#include <QMutex>
#include <QSqlDatabase>

class TcpSocket : public QObject
{
    Q_OBJECT
public:
    //explicit TcpSocket(QTcpSocket *socket,  qintptr socketDescriptor, QObject *parent = 0);
     explicit TcpSocket(qintptr socketDescriptor, QObject *parent = 0);

    ~TcpSocket();

    QTcpSocket *m_socket;

private:

    QString m_ip;
    int m_port;
    qintptr m_socketDescriptor;

    //包头
    qint64 m_frameHeadLength = 12;
    //已收到的字节数
    qint64 m_totalBytes = 0;//要接受数据的总大小
    qint64 m_receivedBytes = 0;//已接受的数据
    QByteArray m_infoBlock;//帧体内容（除去帧头的所有内容）
    QByteArray m_tmpBlock;//临时存储的数据

    QByteArray m_frameHead;//帧头
    QByteArray m_frameContent;//帧体
    QByteArray m_frameTail;//帧尾

    QByteArray m_command;//命令
    QByteArray m_Check;//异或校验
    QByteArray m_length;//长度
    QByteArray m_serialNumber;//序列号
    CommondNumber m_commandNumber;//发送时，填充命令使用

    //心跳统计（10秒刷新），如果3次没有收到，就自动断开和客户端的连接
    QTimer* m_heartBeatTimingStatisticsTimer;
    //是否创建过计时统计
    bool m_isCreateheartBeatTimingStatisticsTimer = false;
    //统计数量
    int m_heartBeatTimingStatisticsTimerCount = 3;
    //心跳互斥锁
    QMutex m_heartBeatTimingStatisticsTimerCountMutex;
    //心跳刷新时间
    int m_heartBeatTimingRefreshTime = 10000;

    QString byteArrayToHexStr(const QByteArray &data);


public:
    /**
     * @brief 得到IP
     * @return
     */
    QString getIP() const;
    /**
     * @brief 得到端口号
     * @return
     */
    int getPort()   const;
    /**
     * @brief 得到套接字描述符
     * @return
     */
    qintptr getSocketDescriptor();

    /**
     * @brief getOrCode：得到异或校验码
     * @param data
     * @return
     */
    QString getOrCode(const QByteArray &data);

    //处理要发送的数据
    QByteArray dealSendData(CommondNumber command, const QString &data);

    QByteArray dealSendData2(const QString &data);

    QByteArray dealSendData3(CommondNumber command, const QByteArray data);

    void dealRecieveData(QByteArray command, QByteArray frameContent);

public slots:
    /**
     * @brief 发送数据
     * @param data
     */
    void sendSocketData(const QString &ip, int port, QByteArray data);

    /**
     * @brief 主界面发送数据
     * @param data
     */
    void sendSocketData(const QString &ip, int port, CommondNumber command, QByteArray data);

private slots:
    /**
     * @brief 断开连接
     */
    void disconnected();
    /**
     * @brief 读取数据
     */
    void readData();

signals:
    /**
     * @brief conveySendData2MainInterface：传递发送的数据非主界面
     * @param ip
     * @param port
     * @param data
     */
    void conveySendData2MainInterface(const QString &ip, int port, const QString &data);


    /**
     * @brief receiveData:发送处理接收到的数据
     * @param ip
     * @param port
     * @param data
     */
    void receiveData(const QString &ip, int port, QByteArray data);

    /**
     * @brief clientDisconnected：客户端断开连接
     * @param socketDescriptor
     */
    void clientDisconnected(qintptr socketDescriptor);

    /**
     * @brief sendLowerComputerChangeInformation：发送下位机改变的数据
     * @param command
     * @param data
     */
    void sendLowerComputerChangeInformation(CommondNumber command, const QByteArray data);

    /**
     * @brief conveyEquipmentStatusType：
     */
    void conveyEquipmentStatusType(int);

    /**
     * @brief 发送收到的数据给主界面
     * @param data
     */
   void sendReceiveData2MainInterface(const QString &ip, int port, const QString &data);

public slots:

    /**
     * @brief 套接字断开连接
     */
    void abort();

    void initializeTcpSocketFunction();

    /**
     * @brief 处理设备登录状态、考试类型、账号信息
     * @param equipmentType
     * @param logStatus
     */
    void dealUserLogStatus(int equipmentStatusType, int examType, int examPatternType, QString account, QHash<QString, QList<int>> faultType);


/** 数据库处理 **/
public:
    //dcl车型考试数据库连接
    QSqlDatabase m_detailInformationDB;

    //学生成绩数据库连接
    QSqlDatabase m_studentGradeDB;

    //总体数据库连接
    QSqlDatabase m_totalInformationDB;


private:
    QString m_detailInformationDatabaseIp = "192.168.0.222";
    int m_detailInformationDatabasePort = 8889;
    QString m_detailInformationDatabaseAccount = "root";
    QString m_detailInformationDatabasePassword = "password";
    QString m_detailInformationDatabaseName = "dcl32k_detail_info_db";

    QString m_detailInformationDatabaseConnectedName = "detailInformationDatabase_mysql_connection";//数据库连接名字




    QString m_studentGradeDatabaseIp = "192.168.0.222";
    int m_studentGradeDatabasePort = 8889;
    QString m_studentGradeDatabaseAccount = "root";
    QString m_studentGradeDatabasePassword = "password";
    QString m_studentGradeDatabaseName = "dcl32k_student_grade_db";

    QString m_studentGradeDatabaseConnectedName = "studentGradeDatabase_mysql_connection";

    QString m_totalInformationDatabaseIp = "192.168.0.222";
    int m_totalInformationDatabasePort = 8889;
    QString m_totalInformationDatabaseAccount = "root";
    QString m_totalInformationDatabasePassword = "password";
    QString m_totalInformationDatabaseName = "train_total_info_db";

    QString m_totalInformationDatabaseConnectedName = "totalInformationDatabase_mysql_connection";

    /**
     * @brief 判断是否首次建立数据库连接
     */
    bool m_createDetailInformationDatabaseConnection = false;
    bool m_createStudentGradeDatabaseConnection = false;
    bool m_createTotalInformationDatabaseConnection = false;

    /**
     * @brief 建立数据库连接
     * @return
     */
    bool CreateDatabaseConnection(QSqlDatabase& sqlDB,
                                  QString ip,
                                  int port,
                                  QString databaseName,
                                  QString databaseAccount,
                                  QString databasePassword,
                                  QString databaseConnectName);

    bool execTransactionSqlSentence(QSqlDatabase mysqlDB,
                                    QList<QString> sqlSentenceList);

//考试
private:
    //检查设备的考试计时统计（秒刷新）
    QTimer* m_executeEquipmentExamTimingStatisticsTimer;
    bool m_isCreateExecuteEquipmentExamTimingStatisticsTimer = false;

    //线路驾驶设备的考试计时统计（秒刷新）
    QTimer* m_routeEquipmentExamTimingStatisticsTimer;

    //捣固设备的考试时间统计
    QTimer* m_tampingHomeworkEquipmentExamTimingStatisticsTimer;

    //考试计时统计（毫秒）
    int m_examTimeoutMsec = 1000*60*35;

    int m1_executeIndex = 0;
    QHash<QString, int> m1_examExecuteStepActualCount;//考试实际执行的计数
    QHash<QString, double> m1_examStepTotalPoint;//考试单步总分数
    QHash<QString, double> m1_examStepDeductPoint;//考试扣分
    QHash<QString, double> m1_examStepObjectPoint;//单步客观得分
    QHash<QString, double> m1_examStepSubobjectPoint;//单步主观得分
    QHash<QString, double> m1_examStepFinalPoint;//单步最终得分
    QHash<QString, int> m1_examSubstepNumberRecord;//单个子步骤的操作机记录（0未操作，1正确，2错误）
    QHash<QString, QString> m1_errorReason;//扣分原因
    QHash<QString, QList<QString>> m1_examSubstepNumberHash;//主步骤对应的子步骤
    QString m1_nowOperatePosition = "";//记录上一阶段的步骤
    double m1_executeEquipmentFinalGrade = 0;//记录环车检查设备的总成绩
    QHash<QString, int> m1_examSituationStatistic;//考试情况统计


    //初始化缓存表格
    void initializeExamineExamTable();

    void dealExamineExamGrade(QString stepId, int executeResult);

    void dealExamineExamDetailSituation();


    //插入考试超时
    void insertExamTableTimeoutResult(QString tableName);

    //发送考试成绩
    void sendExamGrade(int examtype, double grade);


    //统计考试情况
    void statisticExamSituation(QHash<QString, int> examSubstepNumberRecord, QHash<QString, int>& examSituationStatistic);

signals:
    //发送考试情况
    void sendExamSituation(int examtype, QHash<QString, int> examSubstepNumberRecord);

    /**
     * @brief getExamStepSubjectivePoint：得到考试步骤主观成绩
     * @param examType
     */
    void getExamStepSubjectivePoint(int examType);

    void showPartExamTable(int examType);


public slots:

    void calculateExamSituation(int examtype);

};


#endif // TCP_SOCKET_H
